﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Reflection.Emit;
using Framework.ObjectPool;
using System.Reflection;

namespace Framework.ObjectFactory
{
    /// <summary>
    /// WCF代理类构造器
    /// </summary>
    /// <typeparam name="TInterface"></typeparam>
    internal class WCFProxyPoolClassBuilder<TInterface> : PoolClassBuilderBase<TInterface>, ITypeBuilder where TInterface : class
    {
        public WCFProxyPoolClassBuilder()
            : base(typeof(ClientBase<TInterface>))
        {
        }

        /// <summary>
        /// 生成类型
        /// </summary>
        /// <returns></returns>
        protected override Type GenerateTypeImplementation()
        {
            TypeBuilder builder;
            try
            {
                builder = moduleBuilder.DefineType(generatedAssemblyName + "." + generatedClassName, TypeAttributes.Public, baseClassType,
                        new Type[] { typeof(TInterface), typeof(IPoolInstance) });
            }
            catch (Exception ex)
            {
                throw new Exception("未能定义类型 " + generatedClassName + " : " + baseClassType + " , " + typeof(TInterface).Name + " , " + typeof(IPoolInstance).Name, ex);
            }
            if (builder == null)
            {
                throw new Exception("未能定义类型 " + generatedClassName + " : " + baseClassType + " , " + typeof(TInterface).Name + " , " + typeof(IPoolInstance).Name);
            }

            GenerateConstructor(builder);
            GenerateMethodImpl(builder);

            try
            {
                Type generatedType = builder.CreateType();
                return generatedType;
            }
            catch (Exception ex)
            {
                throw new Exception("未能创建类型 " + generatedClassName + " : " + baseClassType + " , " + typeof(TInterface).Name + " , " + typeof(IPoolInstance).Name, ex);
            }
        }

        /// <summary>
        /// 生成类中方法的实现
        /// </summary>
        /// <param name="builder"></param>
        protected override void GenerateMethodImpl(TypeBuilder builder)
        {
            base.GenerateMethodImpl(builder);
            GenerateServiceMethodImpl(builder, typeof(TInterface));
        }

        /// <summary>
        /// 生成服务方法的实现
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="currentType"></param>
        private void GenerateServiceMethodImpl(TypeBuilder builder, Type currentType)
        {
            MethodInfo[] methods = currentType.GetMethods();
            foreach (MethodInfo method in methods)
            {
                Type[] parameterTypes = GetParameters(method.GetParameters());
                MethodBuilder methodBuilder = builder.DefineMethod(method.Name, defaultMethodAttributes, method.ReturnType, parameterTypes);

                methodBuilder.CreateMethodBody(null, 0);
                ILGenerator iLGenerator = methodBuilder.GetILGenerator();
                iLGenerator.Emit(OpCodes.Ldarg_0);
                MethodInfo channelProperty = GetMethodFromBaseClass("get_Channel");
                iLGenerator.EmitCall(OpCodes.Call, channelProperty, null);
                ParameterInfo[] parameters = method.GetParameters();
                for (int index = 0; index < parameterTypes.Length; index++)
                {
                    iLGenerator.Emit(OpCodes.Ldarg, (((short)index) + 1));
                }

                iLGenerator.Emit(OpCodes.Callvirt, method);
                iLGenerator.Emit(OpCodes.Ret);
                builder.DefineMethodOverride(methodBuilder, method);
            }
        }

        /// <summary>
        /// 获取基类的方法
        /// </summary>
        /// <param name="methodName"></param>
        /// <returns></returns>
        protected MethodInfo GetMethodFromBaseClass(string methodName)
        {
            return baseClassType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty);
        }

        /// <summary>
        /// 生成构造函数
        /// </summary>
        /// <param name="builder"></param>
        protected override void GenerateConstructor(TypeBuilder builder)
        {
            if (builder.BaseType.Name.StartsWith("ClientBase") == true && builder.BaseType.Assembly.FullName.StartsWith("System.ServiceModel") == true)
            {
                Type[] constructorParameters = new[] { typeof(System.ServiceModel.Channels.Binding), typeof(EndpointAddress) };
                ConstructorBuilder constructorBuilder = builder.DefineConstructor(MethodAttributes.Public | MethodAttributes.RTSpecialName, CallingConventions.Standard, constructorParameters);
                ILGenerator iLGenerator = constructorBuilder.GetILGenerator();
                iLGenerator.Emit(OpCodes.Ldarg_0);
                iLGenerator.Emit(OpCodes.Ldarg_1);
                iLGenerator.Emit(OpCodes.Ldarg_2);
                ConstructorInfo originalConstructor = baseClassType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, constructorParameters, null);
                iLGenerator.Emit(OpCodes.Call, originalConstructor);
                iLGenerator.Emit(OpCodes.Ret);
            }
        }
    }
}
